package registnet.enlistment;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.apache.torque.TorqueException;

import registnet.dao.Course;
import registnet.dao.CourseDemandPeer;
import registnet.dao.CourseOffering;
import registnet.dao.CourseOfferingPeer;
import registnet.dao.CourseOfferingSlotPeer;
import registnet.dao.CoursePeer;
import registnet.dao.Slot;
import registnet.dao.SlotPeer;
import registnet.dao.Student;
import registnet.dao.StudentPeer;
import registnet.dao.StudentRecommendedCourse;
import registnet.dao.StudentRecommendedCoursePeer;

/**
 * A class that generates a summary of the enlistment process.
 */
public class SummaryGenerator {
	
	/**
	 * A mapping of student and the ratio of his enlisted course units and his recommended course units.
	 */
	private Map<String, Double> studentMap = new HashMap<String, Double>();
	
	/**
	 * A mapping of course and the ratio of its demand and the number of students enlisted in the course.
	 */
	private Map<String, Double> courseMap = new HashMap<String, Double>();
	
	/**
	 * A matrix representation of the student summary.
	 * <pre>
	 * Sample matrix:
	 * 
	 * ##############################
	 * #Below 25# 88                #
	 * #25 to 49# 341               #
	 * #50 to 75# 1231              #
	 * #75 Above# 5813              #
	 * #Total   # 7473              #
	 * #Average # 0.852755825431729 #
	 * ##############################
	 * </pre>
	 */
	private String[][] summaryStudent = new String[6][2];
	
	/**
	 * A matrix representation of the student summary.
	 * 
	 * <pre>
	 * Sample matrix:
	 * 
	 * ##############################
	 * #Below 25# 88                #
	 * #25 to 49# 341               #
	 * #50 to 75# 1231              #
	 * #75 Above# 5813              #
	 * #Total   # 7473              #
	 * #Average # 0.852755825431729 #
	 * ##############################
	 * </pre>
	 */
	private String[][] summaryCourse = new String[6][2];
	
	/**
	 * A matrix representation of the student summary.
	 * 
	 * <pre>
	 * Sample matrix:
	 * 
	 * #################################
	 * #Less than 10            # 1070 #
	 * #Above 10, Less than Max # 440  #
	 * #Maximum                 # 1137 #
	 * #Total                   # 2647 #
	 * #################################
	 * </pre>
	 */
	private String[][] summarySection = new String[4][2];
	
	/**
	 * Default constructor.
	 */
	public SummaryGenerator(){
		
		summaryStudent[0][0] = "Below 25";
		summaryStudent[1][0] = "25 to 49";
		summaryStudent[2][0] = "50 to 75";
		summaryStudent[3][0] = "75 Above";
		summaryStudent[4][0] = "Total";
		summaryStudent[5][0] = "Average";
		
		summaryCourse[0][0] = "Below 25";
		summaryCourse[1][0] = "25 to 49";
		summaryCourse[2][0] = "50 to 75";
		summaryCourse[3][0] = "75 Above";
		summaryCourse[4][0] = "Total";
		summaryCourse[5][0] = "Average";
		
		summarySection[0][0] = "Less than 10";
		summarySection[1][0] = "Above 10, Less than Max";
		summarySection[2][0] = "Maximum";
		summarySection[3][0] = "Total";
		
	}
	
	/**
	 * Generate all enlistment summaries and then create a log.
	 */
	public void doGenerateSummary(){
		doGenerateSummaryStudent();
		doGenerateSummaryCourse();
		doGenerateSummarySection();
		doCreateLog();
	}
	
	/**
	 * Generate student summary of the enlistment process.
	 */
	public void doGenerateSummaryStudent(){
		int[] count = new int[]{0,0,0,0};
		int totalCount = 0;
		double averagePercentage = 0d;
		
		//individual percentage
		for(Student student : new StudentPeer().getAllActiveStudents()){
			int recommendedCoursesUnits = -1;
			int enlistedCoursesUnits = -1;
			Double percentage = 0d;
			Integer semester = (new registnet.dao.SystemPropertiesPeer().getSystemProperties().getSemester() + 1)%3;
			Integer year = new registnet.dao.SystemPropertiesPeer().getSystemProperties().getAcademicYear();
			if(semester==3) year++;
			
			try{
				recommendedCoursesUnits = 0;
				for (StudentRecommendedCourse studentRecommendedCourse : new StudentRecommendedCoursePeer().getRecommendedCoursesByStudent(student.getStudentId())){
					if(studentRecommendedCourse.getCourse().getLectureHoursPerWeek()==0 && studentRecommendedCourse.getCourse().getLaboratoryHoursPerWeek()==0)
						continue;
					if(new CourseOfferingPeer().getCourseOfferings(studentRecommendedCourse.getCourse().getCourseId(), semester, year).size()==0)
						continue;
					CourseOffering courseOfferingTemp = new CourseOfferingPeer().getCourseOfferings(studentRecommendedCourse.getCourse().getCourseId(), semester, year).get(0);
					String lectureDay = courseOfferingTemp.getLectureDay();
					String laboratoryDay = courseOfferingTemp.getLaboratoryDay(); 
					String recitationDay = courseOfferingTemp.getRecitationDay();
					String lectureTime = courseOfferingTemp.getLectureTime();
					String laboratoryTime = courseOfferingTemp.getLaboratoryTime(); 
					String recitationTime = courseOfferingTemp.getRecitationTime();
					boolean hasTask = false;
					if(lectureTime==null || laboratoryTime==null || recitationTime==null)
						continue;
					if(!lectureDay.equals("TBA") && !lectureDay.equals(null) && !lectureDay.equals("")) hasTask = true; 
					if(!laboratoryDay.equals("TBA") && !laboratoryDay.equals(null) && !laboratoryDay.equals("")) hasTask = true;
					if(!recitationDay.equals("TBA") && !recitationDay.equals(null) && !recitationDay.equals("")) hasTask = true;
					if(!hasTask)
						continue;
					
					recommendedCoursesUnits = studentRecommendedCourse.getCourse().getUnits() + recommendedCoursesUnits;
				}
					
			}catch(Exception e){ continue; }
			
			try{
				enlistedCoursesUnits = 0;
				for (Slot slot : new SlotPeer().getAllSlots(student.getStudentId())) 
					enlistedCoursesUnits = slot.getCourseOffering().getCourse().getUnits() + enlistedCoursesUnits;
			}catch(Exception e){ continue; }
			
			if(recommendedCoursesUnits != -1){
				totalCount++;
				if(recommendedCoursesUnits == 0)
					percentage = 1d;
				else
					percentage = (double)((double)enlistedCoursesUnits/(double)recommendedCoursesUnits);
				studentMap.put(student.getStudentNumber(), percentage);
				averagePercentage = averagePercentage + percentage;
			}
			
		}
		
		//percentage range count
		averagePercentage = 0d;
		for (Double percentage : studentMap.values()) {
			if(percentage<.25) count[0]++;
			if(percentage>=.25 && percentage<.50) count[1]++;
			if(percentage>=.50 && percentage<.75) count[2]++;
			if(percentage>=.75) count[3]++;
			averagePercentage = averagePercentage + percentage;
		}
		summaryStudent[0][1] = "" + count[0];
		summaryStudent[1][1] = "" + count[1];
		summaryStudent[2][1] = "" + count[2];
		summaryStudent[3][1] = "" + count[3];
		
		//average percentage
		averagePercentage = averagePercentage / (double)totalCount;
		summaryStudent[5][1] = "" + averagePercentage;
		
		//total count
		summaryStudent[4][1] = "" + totalCount;
	}
	
	/**
	 * Generate course summary of the enlistment process.
	 */
	public void doGenerateSummaryCourse(){
		int[] count = new int[]{0,0,0,0};
		int totalCount = 0;
		double averagePercentage = 0d;
		Integer semester = (new registnet.dao.SystemPropertiesPeer().getSystemProperties().getSemester() + 1)%3;
		Integer year = new registnet.dao.SystemPropertiesPeer().getSystemProperties().getAcademicYear();
		if(semester==3) year++;
		
		//individual percentage
		for(Course course : new CoursePeer().getAllCourses()){
			int courseDemandCount = -1;
			int enlistedStudentsCount = -1;
			Double percentage = 0d;
			
			if(course.getLectureHoursPerWeek()==0 && course.getLaboratoryHoursPerWeek()==0)
				continue;
			if(new CourseOfferingPeer().getCourseOfferings(course.getCourseId(), semester, year).size()==0)
				continue;
			CourseOffering courseOfferingTemp = new CourseOfferingPeer().getCourseOfferings(course.getCourseId(), semester, year).get(0);
			String lectureDay = courseOfferingTemp.getLectureDay();
			String laboratoryDay = courseOfferingTemp.getLaboratoryDay(); 
			String recitationDay = courseOfferingTemp.getRecitationDay();
			String lectureTime = courseOfferingTemp.getLectureTime();
			String laboratoryTime = courseOfferingTemp.getLaboratoryTime(); 
			String recitationTime = courseOfferingTemp.getRecitationTime();
			boolean hasTask = false;
			if(lectureTime==null || laboratoryTime==null || recitationTime==null)
				continue;
			if(!lectureDay.equals("TBA") && !lectureDay.equals(null) && !lectureDay.equals("")) hasTask = true; 
			if(!laboratoryDay.equals("TBA") && !laboratoryDay.equals(null) && !laboratoryDay.equals("")) hasTask = true;
			if(!recitationDay.equals("TBA") && !recitationDay.equals(null) && !recitationDay.equals("")) hasTask = true;
			if(!hasTask)
				continue;
			
			try{
				courseDemandCount = 0;
				courseDemandCount = new CourseDemandPeer().getCourseDemand(course.getCourseId()).getEstimatedDemand();
			}catch(Exception e){ continue; }
			
			try{
				enlistedStudentsCount = 0;
				for(CourseOffering courseOffering : new CourseOfferingPeer().getCourseOfferings(course.getCourseId(), semester, year))
					enlistedStudentsCount = enlistedStudentsCount + (courseOffering.getStudentCount()- new CourseOfferingSlotPeer().getCourseOfferingSlot(courseOffering.getCourseOfferingId()).getRemainingSlotCount());
			}catch(Exception e){ continue; }
			
			if(courseDemandCount != -1){
				totalCount++;
				if(courseDemandCount ==0)
					percentage = 1d;
				else
					percentage = (double)((double)enlistedStudentsCount/(double)courseDemandCount);
				courseMap.put(course.getCourseCode(), percentage);
				averagePercentage = averagePercentage + percentage;
			}
			
		}
		
		//percentage range count
		averagePercentage = 0d;
		for (Double percentage : courseMap.values()) {
			if(percentage<.25) count[0]++;
			if(percentage>=.25 && percentage<.50) count[1]++;
			if(percentage>=.50 && percentage<.75) count[2]++;
			if(percentage>=.75) count[3]++;
			averagePercentage = averagePercentage + percentage;
		}
 		summaryCourse[0][1] = "" + count[0];
		summaryCourse[1][1] = "" + count[1];
		summaryCourse[2][1] = "" + count[2];
		summaryCourse[3][1] = "" + count[3];
		
		//average percentage
		averagePercentage = averagePercentage / (double)totalCount;
		summaryCourse[5][1] = "" + averagePercentage;
		
		//total count
		summaryCourse[4][1] = "" + totalCount;
	}
			
	/**
	 * Generate section summary of the enlistment process.
	 */
	public void doGenerateSummarySection(){
		Integer semester = (new registnet.dao.SystemPropertiesPeer().getSystemProperties().getSemester() + 1)%3;
		Integer year = new registnet.dao.SystemPropertiesPeer().getSystemProperties().getAcademicYear();
		if(semester==3) year++;
		int[] count = new int[]{0,0,0};
		int totalCount = 0;
		
		for (CourseOffering courseOffering : new CourseOfferingPeer().getAllCourseOfferings(semester, year)) {
			
			try {
				if(courseOffering.getCourse().getLectureHoursPerWeek()==0 && courseOffering.getCourse().getLaboratoryHoursPerWeek()==0)
					continue;
				String lectureDay = courseOffering.getLectureDay();
				String laboratoryDay = courseOffering.getLaboratoryDay(); 
				String recitationDay = courseOffering.getRecitationDay();
				String lectureTime = courseOffering.getLectureTime();
				String laboratoryTime = courseOffering.getLaboratoryTime(); 
				String recitationTime = courseOffering.getRecitationTime();
				boolean hasTask = false;
				if(lectureTime==null || laboratoryTime==null || recitationTime==null)
					continue;
				if(!lectureDay.equals("TBA") && !lectureDay.equals(null) && !lectureDay.equals("")) hasTask = true; 
				if(!laboratoryDay.equals("TBA") && !laboratoryDay.equals(null) && !laboratoryDay.equals("")) hasTask = true;
				if(!recitationDay.equals("TBA") && !recitationDay.equals(null) && !recitationDay.equals("")) hasTask = true;
				if(!hasTask)
					continue;
			} catch (TorqueException e1) { continue; }
			
			int studentCount = -1;
			try {
				studentCount = courseOffering.getStudentCount() - new CourseOfferingSlotPeer().getCourseOfferingSlot(courseOffering.getCourseOfferingId()).getRemainingSlotCount();
			} catch (Exception e) { continue; }
			if(studentCount!=1){
				totalCount++;
				if(studentCount<10) count[0]++;
				if(studentCount>=10 && studentCount<courseOffering.getStudentCount()) count[1]++;
				if(studentCount==courseOffering.getStudentCount()) count[2]++;
			}
		}
		summarySection[0][1] = "" + count[0];
		summarySection[1][1] = "" + count[1];
		summarySection[2][1] = "" + count[2];
		
		summarySection[3][1] = "" + totalCount;
	}
	
	/**
	 * Creates a log.
	 */
	public void doCreateLog(){
		FileWriter fileWriter = null;
		BufferedWriter out;
		
		try {
			fileWriter = new FileWriter(System.getProperty("user.dir") + "\\summary_generator.log");
		} catch (IOException e) { e.printStackTrace(); return; }
		out = new BufferedWriter(fileWriter);
		
		try {
			out.append("      Student Summary\n");
			out.append(summaryStudent[0][0] + ": " + summaryStudent[0][1] + "\n");
			out.append(summaryStudent[1][0] + ": " + summaryStudent[1][1] + "\n");
			out.append(summaryStudent[2][0] + ": " + summaryStudent[2][1] + "\n");
			out.append(summaryStudent[3][0] + ": " + summaryStudent[3][1] + "\n");
			out.append(summaryStudent[4][0] + ": " + summaryStudent[4][1] + "\n");
			out.append(summaryStudent[5][0] + ": " + summaryStudent[5][1] + "\n");
			out.append("\n################################\n\n");
			out.append("      Course Summary\n");
			out.append(summaryCourse[0][0] + ": " + summaryCourse[0][1] + "\n");
			out.append(summaryCourse[1][0] + ": " + summaryCourse[1][1] + "\n");
			out.append(summaryCourse[2][0] + ": " + summaryCourse[2][1] + "\n");
			out.append(summaryCourse[3][0] + ": " + summaryCourse[3][1] + "\n");
			out.append(summaryCourse[4][0] + ": " + summaryCourse[4][1] + "\n");
			out.append(summaryCourse[5][0] + ": " + summaryCourse[5][1] + "\n");
			out.append("\n################################\n\n");
			out.append("      Section Summary\n");
			out.append(summarySection[0][0] + ": " + summarySection[0][1] + "\n");
			out.append(summarySection[1][0] + ": " + summarySection[1][1] + "\n");
			out.append(summarySection[2][0] + ": " + summarySection[2][1] + "\n");
			out.append(summarySection[3][0] + ": " + summarySection[3][1] + "\n");
			out.close();
		} catch (IOException e1) { e1.printStackTrace(); return; }
	}

}